import os
import helpers.FileHelper as FileHelper



class LuaPreprocessor:

    def preprocess(self, path, codes, scope):
        for i, line in enumerate(codes):
            indent = " " * LuaPreprocessor.get_indent(line)
            line = line.strip()
            if len(line) == 0:
                continue
            if line.startswith("---#"):
                line = line[4:]
                state = self.status()
                if line.startswith("ifdef "):
                    state *= 1 if line[6:].strip() in scope else 0
                    self.stack.append(state)
                    continue
                elif line.startswith("ifndef "):
                    state *= 0 if line[6:].strip() in scope else 1
                    self.stack.append(state)
                    continue
                elif line.startswith("if "):
                    state *= 1 if eval(line[3:], scope) else 0
                    self.stack.append(state)
                    continue
                elif line.startswith("else"):
                    if len(self.stack) <= 1:
                        raise SyntaxError(self.ERR_FMT.format(path=path, line=i, token="#else"))
                    self.stack.pop()
                    self.stack.append(0 if state == 1 else self.status())
                    continue
                elif line.startswith("endif"):
                    if len(self.stack) <= 1:
                        raise SyntaxError(self.ERR_FMT.format(path=path, line=i, token="#endif"))
                    self.stack.pop()
                    continue
            active = 0 if line.startswith("--//") else 1
            if self.status() != active:
                old_line = codes[i]
                new_line = (indent + line[4:] if active == 0 else "--//" + indent + line) + "\n"
                print("    updating {}:{}:\n<<< {}>>> {}".format(path, i + 1, old_line, new_line))
                codes[i] = new_line
                self.dirty += 1
        if len(self.stack) != 1:
            raise SyntaxError("macro not close.")
        return self.dirty > 0

    def __init__(self):
        self.stack = [1]
        self.dirty = 0

    @staticmethod
    def get_indent(line):
        indent = 0
        for ch in line:
            if ch == ' ':
                indent += 1
            elif ch == '\t':
                indent += 4
            else:
                break
        return indent

    def status(self):
        return self.stack[len(self.stack)-1]

    ERR_FMT = "{path}:{line}: unexpected '{token}'."



def preprocess(scope, *paths):
    print("##### Preprocess With Macro: {}".format(scope))
    root_path = FileHelper.solve_path(*paths)
    for parent_path, dir_names, filenames in os.walk(root_path):
        if os.path.basename(parent_path).startswith("."):
            continue
        for filename in filenames:
            if filename.startswith("."):
                continue
            lua_path = os.path.join(parent_path, filename)
            sub_path = lua_path.replace(root_path, "")
            if filename.endswith(".lua"):
                print("    preprocessing '{}'".format(lua_path))
                codes = FileHelper.r_line(lua_path)
                preprocessor = LuaPreprocessor()
                if preprocessor.preprocess(sub_path, codes, scope):
                    FileHelper.w_line(codes, lua_path, break_line=False)